package com.sim.hook;

import android.app.Application;
import android.content.Context;
import android.os.Message;

import com.sim.util.LogHelper;
import com.sim.util.ThreadUtil;
import com.sim.web.HelloServer;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;

public class HookMain implements IXposedHookLoadPackage {

    public static final String PACKAGE_ID_NORM = "com.android.phone";

    private boolean isHook = false;
    public static Object phoneRIL = null;
    public static Object catService = null;
    public static Object subscriptionInfo = null;

    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
        final String packageName = lpparam.packageName;

        if (PACKAGE_ID_NORM.equals(packageName)) {
            LogHelper.log("hook init");

            if (!isHook) {
                isHook = true;
                hookClientClass(lpparam);
                startWeb();
            }
        }
    }

    private void startWeb() {
        new Thread(() -> {
            try {
                new HelloServer();
            } catch (Exception e) {
                LogHelper.log(e);
            }
        }).start();
    }

    private void hookClientClass(XC_LoadPackage.LoadPackageParam lpparam) {
        XposedHelpers.findAndHookMethod(Application.class, "attach", Context.class, new XC_MethodHook() {
            @Override
            public void afterHookedMethod(MethodHookParam param) throws Throwable {
                ClassLoader cl = ((Context) param.args[0]).getClassLoader();
                final Class RIL = XposedHelpers.findClass("com.android.internal.telephony.RIL", cl);
                final Class SubscriptionController = XposedHelpers.findClass("com.android.internal.telephony.SubscriptionController", cl);

                final Class CatService = XposedHelpers.findClass("com.android.internal.telephony.cat.CatService", cl);
                final Class CommandsInterface = XposedHelpers.findClass("com.android.internal.telephony.CommandsInterface", cl);
                final Class UiccCardApplication = XposedHelpers.findClass("com.android.internal.telephony.uicc.UiccCardApplication", cl);
                final Class IccRecords = XposedHelpers.findClass("com.android.internal.telephony.uicc.IccRecords", cl);
                final Class IccFileHandler = XposedHelpers.findClass("com.android.internal.telephony.uicc.IccFileHandler", cl);
                final Class UiccProfile = XposedHelpers.findClass("com.android.internal.telephony.uicc.UiccProfile", cl);

                final Class CatCmdMessage = XposedHelpers.findClass("com.android.internal.telephony.cat.CatCmdMessage", cl);

                XposedHelpers.findAndHookMethod(RIL, "sendTerminalResponse", String.class, Message.class, new XC_MethodHook() {
                    @Override
                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                        try {
                            phoneRIL = param.thisObject;
                        } catch (Exception e) {
                            LogHelper.log(e);
                        }
                    }
                });

                XposedHelpers.findAndHookMethod(RIL, "sendEnvelope", String.class, Message.class, new XC_MethodHook() {
                    @Override
                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                        try {
                            phoneRIL = param.thisObject;
                        } catch (Exception e) {
                            LogHelper.log(e);
                        }
                    }
                });

                XposedHelpers.findAndHookMethod(SubscriptionController, "getActiveSubscriptionInfo", int.class, String.class, new XC_MethodHook() {
                    @Override
                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                        if (param.getResult() != null) {
                            subscriptionInfo = param.getResult();
                        }
                    }
                });

                XposedHelpers.findAndHookConstructor(CatService, CommandsInterface, UiccCardApplication, IccRecords, Context.class, IccFileHandler, UiccProfile, int.class, new XC_MethodHook() {
                    @Override
                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                        try {
                            catService = param.thisObject;
                            LogHelper.log("统计次数");
                        } catch (Exception e) {
                            LogHelper.log(e);
                        }
                    }
                });

                XposedHelpers.findAndHookMethod(CatService, "broadcastCatCmdIntent", CatCmdMessage, new XC_MethodHook() {

                    @Override
                    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                        try {
                            if (param.args[0] != null) {
                                Method getCommandType = param.args[0].getClass().getMethod("getCmdType");
                                getCommandType.setAccessible(true);
                                Object type = getCommandType.invoke(param.args[0]);
                                if (type != null) {
                                    Method name = type.getClass().getMethod("name");
                                    String commandInt = name.invoke(type).toString();
                                    LogHelper.log("broadcastCatCmdIntent commandInt : " + commandInt);

                                    if (commandInt.equals("SET_UP_IDLE_MODE_TEXT")) {
                                        new Thread(() -> {
                                            try {
                                                String newCurrentCard = getCurrentSimNum(param.args[0]);

                                                if (newCurrentCard.contains("1区") && newCurrentCard.contains("SIM-1")) {
                                                    Constant.currentSim = "1";
                                                    Constant.currentCard = "1";
                                                }

                                                Constant.status = 1;
                                                Constant.newCurrentCard = newCurrentCard;
                                            } catch (Exception e) {
                                                LogHelper.log(e);
                                            }
                                        }).start();
                                    } else if (commandInt.equals("SELECT_ITEM")) {
                                        new Thread(() -> {
                                            ThreadUtil.sleep(100);
                                            checkQueue();
                                        }).start();
                                    }
                                }
                            }
                        } catch (Exception e) {
                            LogHelper.log(e);
                        }
                    }
                });
            }
        });
    }

    public static String switchSim(String sendEnvelopeStr, String sendTerminalResponseStr) {
        String msg = "";
        try {
            if (Constant.checkQueue.size() == 0) {
                Constant.status = 0;
                Constant.checkQueue.add(sendTerminalResponseStr);

                Method sendEnvelope = phoneRIL.getClass().getMethod("sendEnvelope", String.class, Message.class);
                sendEnvelope.invoke(phoneRIL, sendEnvelopeStr, null);

                ThreadUtil.sleep(3000);
                msg = "成功";
            } else {
                Constant.checkQueue.clear();
                msg = "失败";
            }
        } catch (Exception e) {
            LogHelper.log(e);
            msg = "失败";
        }
        return msg;
    }

    public static String getCurrentSimNum(Object cmdMsg) {
        try {
            if (cmdMsg != null) {
                Method geTextMessage = cmdMsg.getClass().getMethod("geTextMessage");
                geTextMessage.setAccessible(true);
                Object mTextMsg = geTextMessage.invoke(cmdMsg);

                if (mTextMsg != null) {
                    Field text = mTextMsg.getClass().getField("text");
                    text.setAccessible(true);
                    Object textObj = text.get(mTextMsg);
                    if (textObj != null) {
                        return textObj.toString();
                    }
                } else {
                    LogHelper.log("mTextMsg == null");
                }
            } else {
                LogHelper.log("cmdMsg == null");
            }
        } catch (Exception e) {
            LogHelper.log(e);
        }

        return "";
    }

    public void checkQueue() {
        String sendTerminalResponseStr = Constant.checkQueue.poll();

        if (sendTerminalResponseStr != null) {
            Constant.checkQueue.clear();
            try {
                Method sendTerminalResponse = phoneRIL.getClass().getMethod("sendTerminalResponse", String.class, Message.class);
                sendTerminalResponse.invoke(phoneRIL, sendTerminalResponseStr, null);
            } catch (Exception e) {
                LogHelper.log(e);
            }
        }
    }
}
